/*
 * File:    ProtocolInterface.java
 * Created: 08-Apr-2006
 * Version: $Id: //depot/bitgate/bsse/src/bitgate/util/service/protocol/ProtocolInterface.java#1 $
 *
 * COPYRIGHT (C) 2006, Bitgate Software, LLC.  All Rights Reserved.
 *
 * software@bitgatesoftware.com
 */

package com.bitgate.util.service.protocol;

import java.nio.channels.Pipe;

import com.bitgate.util.service.client.ClientContext;
import com.bitgate.util.socket.ClientChannel;

/**
 * This is an interface class used with the <code>Service</code> system.  It contains entry points so the <code>Service</code>
 * object can communicate with an unknown protocol that is bound to it.  Once the protocol is bound, all that will be sent
 * to the <code>Service</code>d interface is information about incoming connections, disconnections, and the ability to
 * notify the <code>Service</code> that a connected client is to be forcefully disconnected.
 * <p/>
 * This interface also provides a way for the <code>Service</code>d object to retrieve information from the socket
 * connection, and handle it appropriately.  Each function is called by the <code>Service</code> automatically, and each
 * registered <code>Service</code> protocol must implement the interface features in this class.
 * <p/>
 * With a registered protocol, there is no way to interface with the <code>Service</code> that instantiated it.  Instead, the
 * only method of communication with that <code>Service</code> is through the <code>Pipe</code> that is registered at the time
 * the <code>ProtocolInterface</code>d code is instantiated and initialized.
 *
 * @author Kenji Hollis &lt;kenji@bitgatesoftware.com&gt;
 * @version $Id: //depot/bitgate/bsse/src/bitgate/util/service/protocol/ProtocolInterface.java#1 $
 */
public interface ProtocolInterface
{
    /**
     * Called when the class is to be initialized.  This way, the class can initialize any internal variables it requires, or
     * any system-wide variables that are to be used.
     *
     * @param clusterName The name of the cluster object to be used with this service (if applicable.)
     */
    void init(String clusterName);

    /**
     * Called when a new client connection has been detected.  Sends the <code>ClientContext</code> object as a 
     * reference.  The protocol that implements this interface must store a list of known clients in an <code>ArrayList</code>
     * object, or a <code>HashMap</code> so it can hold context-sensitive information about that client's connection.
     *
     * @param cContext The <code>ClientContext</code> object.
     */
    void addConnection(ClientContext cContext);

    /**
     * Called when a connection is removed from the <code>Service</code>.  This is rarely used, unless the remote client
     * closes the connection abruptly.  It is up to the protocol handler to handle this &quot;exception&quot; state
     * itself.  Failure to do so could cause instability in the protocol handler, and could potentially send confusing
     * messages to the <code>Service</code> object.  (Be aware - confusing disconnection messages sent to the
     * <code>Service</code> object will simply show a logging message.)
     *
     * @param connection The <code>ClientContext</code> to be removed.
     */
    void removeConnection(ClientContext connection);

    /**
     * Registers the communication <code>Pipe</code> object for direct communication with the attached <code>Service</code>.
     * This <code>Pipe</code> object is used to disconnect clients prematurely, or when an error state is detected by
     * the handling protocol.
     *
     * @param pipeObject The <code>Pipe</code> object for IPC to the <code>Service</code>.
     */
    void registerPipe(Pipe pipeObject);
    
    /**
     * Processes the read action from the main <code>Service</code> object.  This is called when the <code>Service</code>'s
     * main <code>select</code> call returns a read from the client, and the data is read.  Subsequent calls to this function
     * may occur while data is read from the client.  It is up to the <code>ProtocolInterface</code>d object to handle
     * this data as it sees fit: the data is not buffered from the <code>Service</code>, it is simply passed through
     * to the handling protocol.
     *
     * @param clientContext The <code>ClientContext</code> object to refer to.
     * @param data The byte array of data sent from the client.
     */
    void processRead(ClientContext clientContext, byte data[]);

    /**
     * Processes the sending of data to the client in a buffered manner.  Instead of having the top-level code write data to
     * the client, this code is used to empty an output buffer to the client that connected up.  The underlying code that
     * writes data should use a pre-formed buffer (ie. written to the filesystem) or something similar to save on memory usage.
     * It is ultimately up to the server to decide how to send data back to the connected client.
     *
     * @param clientContext The <code>ClientContext</code> object to handle writing for.
     * @return <code>true</code> if more data is to be written, <code>false</code> otherwise.
     */
    boolean processWrite(ClientContext clientContext);

    /**
     * Returns a <code>ClientChannel</code> object based on the serial ID.  Since each connection is bound to a serial ID,
     * it can be returned at the time requested.
     *
     * @param clientContext The <code>ClientContext</code> object to look up.
     * @return <code>ClientChannel</code> object.
     */
    ClientChannel getClientChannel(ClientContext clientContext);

    /**
     * Returns the default SelectionKey operation flags on an accepted socket in the main select loop.  If a connection
     * needs read/write operations, it should return <code>OP_READ | OP_WRITE</code>.  Otherwise, if it requires only output
     * to the client, <code>OP_WRITE</code> should be used.  This should be modified so that operations are unique on a per
     * connect basis.  If no selection flag key is required, set this to OP_READ as default.  Setting the key to OP_ACCEPT
     * or OP_CONNECT will throw an exception from the server, and the server will refuse a connection from the client
     * that connected.
     *
     * @return <code>SelectionKey.OP_READ | SelectionKey.OP_WRITE</code> where appropriate.
     */
    int getRegisterOps();

    /**
     * Tells a protocol handler to disconnect all connected clients from the protocol handler.
     */
    void shutdown();
}